/**
 * 
 */

package org.minuframework.file;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import javax.servlet.http.HttpServletResponse;
import org.minuframework.core.io.IOUtils;
import org.minuframework.encrypt.Base64Utils;
import org.minuframework.encrypt.UrlUtils;
import org.minuframework.lang.StringUtils;
import org.minuframework.time.TimeUtils;
import org.minuframework.utils.RandomUtils;
import org.springframework.web.multipart.MultipartFile;
import com.google.common.collect.Maps;

public class FileUtils {

    // ------------------------------------------------------------------------
    // ************************************************************************
    // constants

    public static final String UTF8 = "UTF-8";

    /**
     * 日期格式：年月日时分秒 yyyyMMddHHmmss
     */
    public static final String DEFAULT_FOLDER_STR = "yyyyMMddHHmmss";

    /**
     * 日期格式：年 yyyy
     */
    public static final String YEAR_FOLDER_STR = "yyyy";

    /**
     * 日期格式：年月 yyyyMM
     */
    public static final String MONTH_FOLDER_STR = "yyyyMM";

    /**
     * 日期格式：年月日 yyyyMMdd
     */
    public static final String DAY_FOLDER_STR = "yyyyMMdd";

    /**
     * 斜杠
     */
    public static final String SINGLE_SLASH = "/";

    /**
     * 双斜杠
     */
    public static final String DOUBLE_SLASH = "//";

    /**
     * 反斜杠
     */
    public static final String BACKSLASH = "\\";

    // ************************************************************************
    // public methods

    // ------------------------------------------------------------------------

    /**
     * 读取文件
     * 
     * @param pathname 文件地址
     * @return Properties
     */
    public static Properties load(String pathname) {
        return load(new File(pathname));
    }

    /**
     * 读取文件
     * 
     * @param file 文件地址 File
     * @return Properties
     */
    public static Properties load(File file) {
        return load(file, UTF8);
    }

    /**
     * 读取文件
     * 
     * @param pathname 文件地址
     * @param encoding 编码
     * @return Properties
     */
    public static Properties load(String pathname, String encoding) {
        return load(new File(pathname), encoding);
    }

    /**
     * 读取文件
     * 
     * @param file 文件地址 File
     * @param encoding 编码
     * @return Properties
     */
    public static Properties load(File file, String encoding) {
        Properties p = new Properties();

        InputStreamReader reader = null;
        try {
            InputStream in = new FileInputStream(file);
            reader = new InputStreamReader(in, encoding);
            p.load(reader);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return p;
    }

    // ------------------------------------------------------------------------

    /**
     * 读取文件
     * 
     * @param pathname 文件地址
     * @return List<String>
     */
    public static List<String> asList(String pathname) {
        return asList(new File(pathname));
    }

    /**
     * 读取文件
     * 
     * @param file 文件地址 File
     * @return List<String>
     */
    public static List<String> asList(File file) {
        return asList(file, UTF8);
    }

    /**
     * 读取文件
     * 
     * @param pathname 文件地址
     * @param encoding 编码
     * @return List<String>
     */
    public static List<String> asList(String pathname, String encoding) {
        return asList(new File(pathname), encoding);
    }

    /**
     * 读取文件
     * 
     * @param file 文件地址 File
     * @param encoding 编码
     * @return List<String>
     */
    public static List<String> asList(File file, String encoding) {
        List<String> result = new ArrayList<String>();

        BufferedReader buf = null;
        try {
            InputStream in = new FileInputStream(file);
            InputStreamReader reader = new InputStreamReader(in, encoding);
            buf = new BufferedReader(reader);
            String read;
            while ((read = buf.readLine()) != null) {
                result.add(read);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (buf != null) {
                    buf.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    // ------------------------------------------------------------------------

    /**
     * 读取文件
     * 
     * @param pathname 文件地址
     * @return String[]
     */
    public static String[] asArray(String pathname) {
        return asArray(new File(pathname));
    }

    /**
     * 读取文件
     * 
     * @param file 文件地址 File
     * @return String[]
     */
    public static String[] asArray(File file) {
        return asArray(file, UTF8);
    }

    /**
     * 读取文件
     * 
     * @param pathname 文件地址
     * @param encoding 编码
     * @return String[]
     */
    public static String[] asArray(String pathname, String encoding) {
        return asArray(new File(pathname), encoding);
    }

    /**
     * 读取文件
     * 
     * @param file 文件地址 File
     * @param encoding 编码
     * @return String[]
     */
    public static String[] asArray(File file, String encoding) {
        List<String> result = asList(file, encoding);
        return result.toArray(new String[result.size()]);
    }

    // ------------------------------------------------------------------------

    /**
     * 读取文件
     * 
     * @param pathname 文件地址
     * @return Map<Object, Object>
     */
    public static Map<Object, Object> asMap(String pathname) {
        return asMap(new File(pathname));
    }

    /**
     * 读取文件
     * 
     * @param file 文件地址 File
     * @return Map<Object, Object>
     */
    public static Map<Object, Object> asMap(File file) {
        return asMap(file, UTF8);
    }

    /**
     * 读取文件
     * 
     * @param pathname 文件地址
     * @param encoding 编码
     * @return Map<Object, Object>
     */
    public static Map<Object, Object> asMap(String pathname, String encoding) {
        return asMap(new File(pathname), encoding);
    }

    /**
     * 读取文件
     * 
     * @param file 文件地址 File
     * @param encoding 编码
     * @return Map<Object, Object>
     */
    public static Map<Object, Object> asMap(File file, String encoding) {
        Map<Object, Object> params = Maps.newHashMap();
        Properties propertiesFile = load(file, encoding);
        for (Entry<Object, Object> entry : propertiesFile.entrySet()) {
            params.put(entry.getKey(), entry.getValue());
        }
        return params;
    }

    // ------------------------------------------------------------------------

    /**
     * 复制文件
     * 
     * @param filename 上传文件地址
     * @param target 文件存放地址
     * @throws IOException
     */
    public static void copy(final String filename, final String target) throws IOException {
        copy(new File(filename), new File(target));
    }

    /**
     * 复制文件
     * 
     * @param filename 上传文件地址
     * @param target 文件存放地址
     * @throws IOException
     */
    public static void copy(final File file, final File target) throws IOException {
        FileInputStream input = null;
        FileOutputStream output = null;
        try {
            input = new FileInputStream(file);
            output = new FileOutputStream(target);
            IOUtils.copy(input, output);
        } finally {
            IOUtils.close(output);
            IOUtils.close(input);
        }
    }

    public static void copy(final MultipartFile multipartFile, final String target)
            throws IOException {
        copy(multipartFile, new File(target));
    }

    public static void copy(final MultipartFile multipartFile, final File target)
            throws IOException {
        InputStream input = null;
        FileOutputStream output = null;
        try {
            input = multipartFile.getInputStream();
            output = new FileOutputStream(target);
            IOUtils.copy(input, output);
        } finally {
            IOUtils.close(output);
            IOUtils.close(input);
        }
    }

    public static void write(final MultipartFile multipartFile, final File target)
            throws IllegalStateException, IOException {
        target.createNewFile();
        multipartFile.transferTo(target);
    }

    /**
     * 合并文件
     * 
     * @param fileList 文件列表
     * @param target 目标路径
     * @throws IOException
     */
    @SuppressWarnings("resource")
    public static void write(List<File> fileList, File target) throws IOException {
        FileChannel in = null;
        FileChannel out = null;
        try {
            out = new FileOutputStream(target).getChannel();
            for (File item : fileList) {
                in = new FileInputStream(item).getChannel();
                IOUtils.write(in, out);
                in.close();
            }
        } finally {
            IOUtils.close(out);
            IOUtils.close(in);
        }
    }

    // ------------------------------------------------------------------------

    /**
     * base64生成文件
     * 
     * @param imgstr
     * @param file 文件存放路径
     * @param prefix 前缀
     * @param suffix 后缀
     * @return String
     * @deprecated
     */
    public static String generateImage(String imgstr, String file, String prefix, int suffix) {
        return generateImage(imgstr, new File(file), prefix, suffix);
    }

    /**
     * base64生成文件
     * 
     * @param imgstr base64编码
     * @param file 文件存放路径
     * @param prefix 前缀
     * @param suffix 后缀
     * @return String
     * @deprecated
     */
    public static String generateImage(String imgstr, File file, String prefix, int suffix) {
        String suffixName = Base64Utils.suffix(imgstr);
        String filename = randomUUId(prefix, suffix, suffixName);
        File path = new File(file, getFolderByMonth());
        isFile(path);
        File realPath = new File(path, filename);
        if (Base64Utils.generateImage(imgstr, realPath)) {
            return realPath.toString();
        }
        return null;
    }

    /**
     * base64生成文件
     * 
     * @param imgstr base64编码
     * @param filename 文件存放路径
     * @return boolean
     * @deprecated
     */
    public static boolean generateImage(String imgstr, String filename) {
        return Base64Utils.generateImage(imgstr, filename);
    }

    /**
     * base64生成文件
     * 
     * @param imgstr base64编码
     * @param file 文件存放路径
     * @return boolean
     * @deprecated
     */
    public static boolean generateImage(String imgstr, File file) {
        return Base64Utils.generateImage(imgstr, file);
    }

    // ------------------------------------------------------------------------

    /**
     * 删除文件
     * 
     * @param filename 文件路径
     * @return boolean
     * @throws Exception
     */
    public static boolean delete(final String filename) {
        return delete(new File(filename));
    }

    /**
     * 删除文件
     * 
     * @param file 文件路径
     * @return boolean
     * @throws Exception
     */
    public static boolean delete(final File file) {
        if (file != null && file.exists()) {
            if (file.isDirectory()) {
                return deleteDir(file);
            } else if (file.isFile()) {
                return deleteFile(file);
            }
        }
        return false;
    }

    /**
     * 删除文件
     * 
     * @param files 文件路径数组
     * @return boolean
     * @throws Exception
     */
    public static boolean delete(String[] files) {
        if (files == null || files.length <= 0) {
            return false;
        }
        for (String item : files) {
            if (!delete(item)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 删除文件
     * 
     * @param files 文件路径数组
     * @return boolean
     * @throws Exception
     */
    public static boolean delete(File[] files) {
        if (files == null || files.length <= 0) {
            return false;
        }
        for (File item : files) {
            if (!delete(item)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 删除文件
     * 
     * @param fileList 文件路径集合
     * @return boolean
     * @throws Exception
     */
    public static boolean delete(List<File> fileList) {
        if (fileList == null || fileList.isEmpty()) {
            return false;
        }
        for (File item : fileList) {
            if (!delete(item)) {
                return false;
            }
        }
        return true;
    }

    private static boolean deleteFile(final File file) {
        return file.delete();
    }

    private static boolean deleteDir(final File file) {
        String[] dirs = file.list();
        for (int i = 0; i < dirs.length; i++) {
            if (!delete(new File(file, dirs[i]))) {
                return false;
            }
        }
        return file.delete();
    }

    // ------------------------------------------------------------------------

    /**
     * 读取文件
     * 
     * @param response HttpServletResponse
     * @param filename 文件路径
     * @throws IOException
     */
    public static void write(final HttpServletResponse response, final String filename)
            throws IOException {
        write(response, new File(filename));
    }

    /**
     * 读取文件
     * 
     * @param response HttpServletResponse
     * @param file 文件路径
     * @throws IOException
     */
    public static void write(final HttpServletResponse response, final File file)
            throws IOException {
        FileInputStream input = null;
        BufferedInputStream buffer = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(file);
            buffer = new BufferedInputStream(input);
            output = response.getOutputStream();
            IOUtils.write(buffer, output);
        } finally {
            IOUtils.close(output);
            IOUtils.close(buffer);
            IOUtils.close(input);
        }
    }

    // ------------------------------------------------------------------------

    /**
     * 文件下载
     * 
     * @param response HttpServletResponse
     * @param file 文件路径
     * @throws IOException
     */
    public static void down(final HttpServletResponse response, final File file)
            throws IOException {
        response.setContentType("application/force-download");// 设置强制下载不打开
        response.addHeader("Content-Disposition", "attachment;filename=" + file);// 设置文件名
        write(response, file);
    }

    /**
     * 复制文件
     * 
     * @param fileurl 文件地址httpurl
     * @param target 目标地址
     * @throws IOException
     */
    public static void down(final String httpurl, final String target) throws IOException {
        URL url = null;
        DataInputStream in = null;
        FileOutputStream out = null;
        ByteArrayOutputStream output = null;
        try {
            url = new URL(httpurl);
            in = new DataInputStream(url.openStream());
            out = new FileOutputStream(new File(target));
            output = new ByteArrayOutputStream();
            IOUtils.write(in, output);
            out.write(output.toByteArray());
        } finally {
            IOUtils.close(out);
            IOUtils.close(output);
            IOUtils.close(in);
        }
    }

    // ------------------------------------------------------------------------

    /**
     * 获取完整路径
     * 
     * @param target 上传路径
     * @param prefix 前缀
     * @param suffix 后缀
     * @param suffixName 后缀名
     * @return File
     */
    public static File buildPath(String target, String prefix, int suffix, String suffixName) {
        return buildPath(new File(target), prefix, suffix, suffixName);
    }

    /**
     * 获取完整路径
     * 
     * @param target 上传路径
     * @param prefix 前缀
     * @param suffix 后缀
     * @param suffixName 后缀名
     * @return File
     */
    public static File buildPath(File target, String prefix, int suffix, String suffixName) {
        String uuid = randomUUId(prefix, suffix, suffixName);
        File realFile = new File(target, uuid);
        return realFile;
    }

    /**
     * 检测路径是否存在
     * 
     * @param file 路径
     */
    public static void isFile(File file) {
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 获取文件夹（年）
     * 
     * @return String
     */
    public static String getFolderByYear() {
        return TimeUtils.formatDateTime(YEAR_FOLDER_STR);
    }

    /**
     * 获取文件夹（年月）
     * 
     * @return String
     */
    public static String getFolderByMonth() {
        return TimeUtils.formatDateTime(MONTH_FOLDER_STR);
    }

    /**
     * 获取文件夹（年月日）
     * 
     * @return String
     */
    public static String getFolderByDay() {
        return TimeUtils.formatDateTime(DEFAULT_FOLDER_STR);
    }

    /**
     * 生成文件名
     * 
     * @param prefix 前缀
     * @param suffix 后缀
     * @param suffixName 后缀名
     * @return String
     */
    public static String randomUUId(String prefix, int suffix, String suffixName) {
        StringBuilder result = new StringBuilder();
        result.append(RandomUtils.randomUUId(RandomUtils.DATATIME, prefix, suffix, 3));
        if (StringUtils.isNotEmpty(suffixName)) {
            result.append(suffixName);
        }
        return result.toString();
    }

    /**
     * 获取文件后缀名
     * 
     * @param name 文件名
     * @return 文件后缀名
     */
    public static String suffix(String name) {
        try {
            return name.substring(name.lastIndexOf("."), name.length());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取文件后缀名
     * 
     * @param file 文件路径
     * @return 文件后缀名
     */
    public static String suffix(File file) {
        try {
            String name = file.getName();
            return name.substring(name.lastIndexOf("."), name.length());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取文件真实路径
     * 
     * @param name 文件名
     * @return 文件真实路径 URL
     */
    public static String pathname(String name) {
        StringBuilder result = new StringBuilder();
        try {
            URL url = Thread.currentThread().getContextClassLoader().getResource(name);
            String param = url.getFile();
            result.append(UrlUtils.urlDencoder(param, UTF8));
        } catch (UnsupportedEncodingException e) {
        }
        return result.toString();
    }

}
